﻿using System;
using System.Linq;
using System.Threading;
using System.Collections.Generic;

using SimbaRGVMonitor.Models;
using SimbaRGVMonitor.Common.Data;
using SimbaRGVMonitor.Common.Utils;

namespace SimbaRGVMonitor.Controllers
{
    partial class ScheduleController
    {
        public ScheduleController()
        {
            updateThread = new Thread(LoopUpdate) { IsBackground = true };
            InitializeSettings();
        }

        //====================================================================================================
        //以上是类型构造函数
        //----------------------------------------------------------------------------------------------------
        //以下是类型字段
        //====================================================================================================

        private bool started;
        private readonly Thread updateThread;
        private readonly MonitorTcpJob[] tcpJobs = CreateTcpJobs().ToArray();
        private readonly MonitorTcpDataBuffer buffer = new MonitorTcpDataBuffer();
        private readonly MonitorTcpAgent tcpAgent = MonitorTcpAgentFactory.CreateSchedulerTcpAgent("Map");

        //====================================================================================================
        //以上是类型字段
        //----------------------------------------------------------------------------------------------------
        //以下是类型事件及触发函数
        //====================================================================================================

        public event EventHandler<SchedulerItemsUpdatedEventArgs<Robot>> RobotsUpdated;
        private void OnRobotsUpdated(IEnumerable<Robot> robots)
        {
            if(started)
            {
                var e = new SchedulerItemsUpdatedEventArgs<Robot>(robots);
                RobotsUpdated.TriggerEvent(this, e);
            }
        }

        public event EventHandler<SchedulerItemsUpdatedEventArgs<Path>> PathsUpdated;
        private void OnPathsUpdated(IEnumerable<Path> paths)
        {
            if (started)
            {
                var e = new SchedulerItemsUpdatedEventArgs<Path>(paths);
                PathsUpdated.TriggerEvent(this, e);
            }
        }

        public event EventHandler<SchedulerItemsUpdatedEventArgs<Vertex>> VertexesUpdated;
        private void OnVertexesUpdated(IEnumerable<Vertex> vertices)
        {
            if (started)
            {
                var e = new SchedulerItemsUpdatedEventArgs<Vertex>(vertices);
                VertexesUpdated.TriggerEvent(this, e);
            }
        }

        //====================================================================================================
        //以上是类型事件及触发函数
        //----------------------------------------------------------------------------------------------------
        //以下是初始化设置
        //====================================================================================================

        private void InitializeSettings()
        {
            tcpAgent.OpenAsync();
            tcpAgent.MessageReceived += WhenMessageReceived;

            updateThread.Start();
        }

        //====================================================================================================
        //以上是初始化设置
        //----------------------------------------------------------------------------------------------------
        //以下是开始及停止
        //====================================================================================================

        public void Start()
        {
            started = true;
        }

        public void Stop()
        {
            started = false;
        }

        //====================================================================================================
        //以上是开始及停止
        //----------------------------------------------------------------------------------------------------
        //以下是TCP驱动更新
        //====================================================================================================

        private void LoopUpdate()
        {
            const int interval = 100;
            while(true)
            {
                if (started && tcpAgent.Connected)
                {
                    foreach (var tcpJob in tcpJobs)
                    {
                        var timeout = TimeSpan.FromSeconds(10);
                        tcpJob.Excute(interval, timeout, tcpAgent, buffer);
                    }
                }

                Thread.Sleep(interval);
            }
        }

        //====================================================================================================
        //以上是TCP驱动更新
        //----------------------------------------------------------------------------------------------------
        //以下是TCP事件侦听
        //====================================================================================================

        private void WhenMessageReceived(object sender, MonitorTcpAgentMessageReceivedEventArgs e)
        {
            var message = e.Message;
            const string serviceNameKey = "ServiceName";
            var jsonNodes = SerializeUtil.DeserializeFromJson<JsonNodes>(message);
            if (jsonNodes.ContainsKey(serviceNameKey) == false)
            {
                return;
            }

            var serviceName = jsonNodes.GetString(serviceNameKey);
            if (serviceName == "Robot")
            {
                var update = SerializeUtil.DeserializeFromJson<RobotUpdate>(message);
                var robot = CreateRobot(update);
                var robots = new[] { robot };
                OnRobotsUpdated(robots);
            }
            else if (serviceName == "Path")
            {
                var response = SerializeUtil.DeserializeFromJson<PathResponse>(message);
                var pathDatas = SerializeUtil.DeserializeFromJson<PathData[]>(response.Paths);
                var paths = pathDatas.Select(item => CreatePath(item)).ToArray();
                OnPathsUpdated(paths);

                buffer.PushData(response);
            }
            else if (serviceName == "Vertex")
            {
                var response = SerializeUtil.DeserializeFromJson<VertexResponse>(message);
                var vertexDatas = SerializeUtil.DeserializeFromJson<VertexData[]>(response.Vertexes);
                var vertexes = vertexDatas.Select(item => CreateVertex(item)).ToArray();
                OnVertexesUpdated(vertexes);

                buffer.PushData(response);
            }
        }

        //====================================================================================================
        //以上是TCP事件侦听
        //----------------------------------------------------------------------------------------------------
        //以下是创建模型
        //====================================================================================================

        private Robot CreateRobot(RobotUpdate update)
        {
            var robotNo = update.RobotNo;
            var moveStatus = update.MoveStatus;
            var px = update.Px;
            var py = update.Py;
            var currentVertex = update.CurrentVertex;
            var yaw = update.Yaw;
            var taskAction = update.TaskAction;
            var taskStatus = update.TaskStatus;
            var packetState = update.PacketState;
            return new Robot(robotNo, moveStatus, px, py, currentVertex, yaw, taskAction, taskStatus, packetState);
        }

        private Path CreatePath(PathData data)
        {
            var pathNo = data.PathNo;
            var pathDestA = data.PathDestA;
            var startVertex = data.StartVertex;
            var endVertex = data.EndVertex;
            return new Path(pathNo, pathDestA, startVertex, endVertex);
        }

        private Vertex CreateVertex(VertexData data)
        {
            var vertexNo = data.VertexNo;
            var positionX = data.PositionX;
            var positionY = data.PositionY;
            var isOccupied = data.IsOccupied;
            var arrivedRobot = data.ArrivedRobot;
            return new Vertex(vertexNo, positionX, positionY, isOccupied, arrivedRobot); ;
        }

        //====================================================================================================
        //以上是创建模型
        //----------------------------------------------------------------------------------------------------
        //以下是创建TCP定时任务
        //====================================================================================================

        private static IEnumerable<MonitorTcpJob> CreateTcpJobs()
        {
            var vertexRequest = new VertexRequest { ServiceName = "Vertex", demand = "all", monitorNo = "SimbaRobot001" };
            yield return new MonitorTcpJob(3000, vertexRequest, data => data is VertexResponse);
            var pathRequest = new PathRequest { ServiceName = "Path", demand = "all", monitorNo = "SimbaRobot001" };
            yield return new MonitorTcpJob(5000, pathRequest, data => data is PathResponse);
            var monitorRequest = new MonitorRequest { ServiceName = "Monitor", demand = "register", monitorNo = "SimbaRobot001" };
            yield return new MonitorTcpJob(100, monitorRequest);
        }
    }
}
